<?php
/**
 * Created by PhpStorm.
 * User: wangjie
 * Date: 2020/10/16
 * Time: 17:39
 */
namespace App\Api\Controllers\Glow;


use App\Models\WincodeStore;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use App\Api\Controllers\BaseController as BBaseController;

/**
 * 接口遵循以下规范：
 * 1. 接口采用 POST 方式提交数据，数据格式均为 XML 格式，根节点名为 xml
 * 2. 数据采用 UTF-8 字符编码
 * 3. 请求和接收数据均需要校验签名， 签名算法 使用 MD5
 * 4. 处理应答时先判断协议字段返回，再判断业务返回，最后判断交易状态
 * Class BaseController
 * @package App\Api\Controllers\WinCode
 */
class BaseController extends BBaseController
{
    public $postCharset = "UTF-8";
    private $fileCharset = "UTF-8";

    //公共参数
    public $version = "1.0.0"; //接口版本
    public $method = ""; //处理方式(根据请求的接口决定),pay.weixin.jsapi
    public $charset = "UTF-8"; //否,字符集,可选值，默认为UTF-8
    public $sign_type = "MD5"; //否,签名方式,签名类型，取值：MD5，默认：MD5
    public $sign = ""; //签名,MD5签名结果
//    public $appid = ""; //应用ID,码上赢聚合支付分配的应用ID
    public $nonce_str = ""; //随机字符串，不长于32位
    //根据接入方式的不同，请求中还需要包括如下附加参数
    public $device_id = ""; //否,设备ID,ERP/POS厂商接入,门店二维码ID或自定义设备编号
    public $mch_id = ""; //否,商户,商户ID,商户编号

    public $needpage = false; //默认不要分页
    public $l = 15;
    public $p = 1;
    public $t = 0;
    public $status = 1;
    public $message = 'ok';

    public $key = "FA217EE7D519894FD66BA660FFD3E5BE";
    public $agent_id = 'agent_2327_998797';

    /**
     * 返回数据
     *
     * @param $data
     * @return \Illuminate\Http\JsonResponse
     */
    //处理完返回
    public function return_data($data)
    {
        $key = $this->key;
        $string = $this->getSignContent($data) . '&key=' . $key;
        $data['sign'] = strtoupper(md5($string));
        return $data['sign'];
    }


    /**
     * 校验md5
     *
     * @param $data
     * @return array
     */
    public function check_md5($data)
    {
        try {
            $sign = $data['sign'];
            $data['sign'] = null;
            $string = $this->getSignContent($data);
//            Log::info('校验md5');
//            Log::info($data);
//            Log::info(strtoupper(md5($string)));

            if ($sign == strtoupper(md5($string))) {
                return [
                    'return_code' => 'SUCCESS',
                    'return_msg' => '验证通过'
                ];
            } else {
                return [
                    'return_code' => 'FALL',
                    'return_msg' => '验证不通过'
                ];
            }
        } catch (\Exception $e) {
            return [
                'return_code' => 'FALL',
                'return_msg' => $e->getMessage().' | '.$e->getFile().' | '.$e->getLine()
            ];
        }
    }


    //参数拼接
    public function getSignContent($params)
    {
        ksort($params);

        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            //空值和数组,不参与签名组串
            if (is_array($v) || true === $this->checkEmpty($v)) {
                continue;
            }

            $v = $this->characet($v, $this->postCharset); // 转换成目标字符集

            if ($i == 0) {
                $stringToBeSigned .= "$k" . "=" . "$v";
            } else {
                $stringToBeSigned .= "&" . "$k" . "=" . "$v";
            }

            $i++;
        }

        unset ($k, $v);
        return $stringToBeSigned;
    }


    /**
     * 转换字符集编码
     * @param $data
     * @param $targetCharset
     * @return string
     */
    function characet($data, $targetCharset)
    {
        if (!empty($data)) {
            $fileType = $this->fileCharset;
            if (strcasecmp($fileType, $targetCharset) != 0) {
                $data = mb_convert_encoding($data, $targetCharset);
//				$data = iconv($fileType, $targetCharset.'//IGNORE', $data);
            }
        }

        return $data;
    }


    /**
     * 校验$value是否非空
     *  if not set ,return true;
     *    if is null , return true;
     **/
    protected function checkEmpty($value)
    {
        $value = trim($value);

        if (!isset($value))
            return true;
        if ($value === null)
            return true;
        if ($value === "")
            return true;
        if ($value === [])
            return true;
        if (empty($value))
            return true;

        return false;
    }

       /*
        curl发送数据
    */
    static function curl($data, $url)
    {
        //启动一个CURL会话
        $ch = curl_init();
        $data_str = json_encode($data);
        // 设置curl允许执行的最长秒数
        curl_setopt($ch, CURLOPT_TIMEOUT, 120);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        // 获取的信息以文件流的形式返回，而不是直接输出。
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        //发送一个常规的POST请求。
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        //要传送的所有数据
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data_str);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
             'Content-Type: application/json; charset=utf-8',
             'Content-Length: ' . strlen($data_str))
        );
        // 执行操作
        $res = curl_exec($ch);
        $response = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if ($res == NULL) {
            curl_close($ch);
            return false;
        } else if ($response != "200") {
            curl_close($ch);
            return false;
        }
        curl_close($ch);
        return $res;
    }


    /**
     * 校验必填字段
     *
     * @param $check
     * @param $data
     * @return mixed
     */
    public function check_required($check, $data)
    {
        $rules = [];
        $attributes = [];
        foreach ($data as $k => $v) {
            $rules[$k] = 'required';
            $attributes[$k] = $v;
        }
        $messages = [
            'required' => ':attribute不能为空',
        ];
        $validator = Validator::make($check, $rules,
            $messages, $attributes);
        $message = $validator->getMessageBag();

        return $message->first();
    }


    /**
     * 返回数据格式化
     *
     * @param array $cin
     * @return \Illuminate\Http\JsonResponse
     */
    public function format($cin = [])
    {
        $data = [
            'l' => $this->l, //每页显示多少条
            'p' => $this->p, //当前页
            't' => $this->t, //当前页
            'status' => $this->status,
            'message' => $this->message,
            'data' => $cin
        ];

        if ($this->needpage) {
            $data['l'] = $this->l;
            $data['p'] = $this->p;
            $data['t'] = $this->t;
        }

        return response()->json($data);
    }


    /**
     * 返回分页数据
     *
     * @param $obj
     * @param string $request
     * @return mixed
     */
    public function page($obj, $request = '')
    {
        if (empty($request))
            $request = app('request');

        $this->p = abs(trim($request->get('p', 1)));
        $this->l = abs(trim($request->get('l', 15)));

        $this->needpage = true;

        $start = abs(($this->p - 1) * $this->l);

        return $obj->offset($start)->limit($this->l);
    }


    /**
     * 输出xml字符
     *
     * @param $data
     * @return string
     */
    public function ToXml($data)
    {
        $xml = "<xml>";

        foreach ($data as $key => $val) {
//            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
//            } else {
//                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
//            }
        }

        $xml .= "</xml>";

        return $xml;
    }


    /**
     * 将XML转为array
     *
     * @param $xml
     * @return mixed
     */
    public function xml_to_array($xml)
    {
        if (!$xml) {
            die("xml数据异常！");
        }

        libxml_disable_entity_loader(true); //禁止引用外部xml实体
        $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

        return $values;
    }


    /**
     * 32位随机数
     * @return string
     */
    public function nonceStr()
    {
        return md5(mt_rand(1000, 9999).time());
    }


    /**
     * 生产激活码
     * @param int $len
     * @return int|mixed
     */
    protected function createDeviceToken($len = 6)
    {
        $string = rand( pow(10, ($len - 1) ), pow(10, $len) - 1 );

        $isExit = WincodeStore::where('activation_code', $string)->first();
        if (!$isExit) {
            return $string;
        } else {
            $this->createDeviceToken(7);
        }
    }


    /**
     * 生产设备号
     * @param int $len
     * @return int|mixed
     */
    public function createDeviceId($len = 6)
    {
        $string = substr(time(), 6, $len).mt_rand(1000, 9999);

        $isExit = WincodeStore::where('device_id', $string)->first();
        if (!$isExit) {
            return $string;
        } else {
            $this->createDeviceId(6);
        }
    }


}
